package com.sardine.base.hbase.persister;

import com.sardine.base.hbase.HConfiguration;
import com.sardine.base.hbase.constants.IdGeneratorEnum;
import com.sardine.base.hbase.exception.HException;
import com.sardine.base.hbase.generator.Generator;
import com.sardine.base.hbase.generator.MD5HashGeneratorImpl;
import com.sardine.base.utils.DateUtils;
import com.sardine.base.utils.JsonUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.Serializable;
import java.lang.reflect.Field;
import java.text.ParseException;
import java.util.Date;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

/**
 * 上海京东到家元信信息技术有限公司<br>
 * Created with IntelliJ IDEA.
 * Date:2017/11/21
 * Time:21:08
 *
 * @author daifeng<br>
 *         daifeng@imdada.cn
 * @since JDK 1.7 <br>
 * Copyright (c) 2017 imdada System Incorporated All Rights Reserved.
 */
public class DefaultHEntityAdhesive implements HEntityAdhesive {
    private static final Logger logger = LoggerFactory.getLogger(DefaultHEntityAdhesive.class);
    private Generator generator = new MD5HashGeneratorImpl();
    /**
     * hbase的配置中心
     */
    private HConfiguration configuration;

    /**
     * 基本类型、包装类型、String类型
     */
    private static final Set<String> types = new HashSet<>();

    static {
        types.add("java.util.Date");
        types.add("java.lang.Integer");
        types.add("java.lang.Double");
        types.add("java.lang.Float");
        types.add("java.lang.Long");
        types.add("java.lang.Short");
        types.add("java.lang.Byte");
        types.add("java.lang.Boolean");
        types.add("java.lang.Character");
        types.add("java.lang.String");
        types.add("int");
        types.add("double");
        types.add("long");
        types.add("short");
        types.add("byte");
        types.add("boolean");
        types.add("char");
        types.add("float");
    }


    public DefaultHEntityAdhesive(HConfiguration configuration) {
        this.configuration = configuration;
    }

    /**
     * 将数据对象转换成hbase数据模型
     * @param skeleton
     * @param obj
     * @return
     */
    @Override
    public HEntity getPerSister(HEntitySkeleton skeleton, Object obj) {
        HEntity entity = new HEntity();
        entity.setTableSpace(configuration.getTableSpace());
        entity.setRowKey(getRowKey(skeleton.getRowKey(), obj, skeleton.getGeneratorEnum()));
        entity.setTableName(skeleton.getTableName());
        List<HEntity.DataModel> dataFiled = entity.getDataModelList();
        List<HEntitySkeleton.FiledDesc> filedDescList = skeleton.getFiledDescList();
        for (HEntitySkeleton.FiledDesc filedDesc : filedDescList) {
            HEntity.DataModel fieldValue = getFieldValue(filedDesc, obj);
            if (fieldValue != null) {
                dataFiled.add(fieldValue);
            }
        }
        return entity;
    }

    /**
     * 讲base entity 转换成数据对象
     *
     * @param skeleton
     * @param hEntity
     * @param <T>
     * @return
     */
    public <T> T decoderModel(HEntitySkeleton<T> skeleton, HEntity hEntity) {
        T t = null;
        try {
            Class<T> aClass = skeleton.getClassName();
            List<HEntity.DataModel> dataModelList = hEntity.getDataModelList();
            //得到属性描述
            List<HEntitySkeleton.FiledDesc> filedDescList = skeleton.getFiledDescList();
            t = aClass.newInstance();
            //组合数据
            if (filedDescList != null) {
                for (HEntitySkeleton.FiledDesc fieldDesc : filedDescList) {
                    Field field = fieldDesc.getFiled();
                    //抑制Java对其的检查
                    field.setAccessible(true);
                    //得到类型
                    String typeName = fieldDesc.getType();
                    String fieldQualifier = fieldDesc.getQualifier();
                    String value = null;
                    for (HEntity.DataModel dataModel : dataModelList) {
                        String qualifier = dataModel.getQualifier();
                        if (qualifier.equals(fieldQualifier)) {
                            value = dataModel.getFieldValue();
                            break;//退出本层循环
                        }
                    }
                    if (value != null) {
                        Object obj = paseBaseType(typeName, value);
                        field.set(t, obj);
                    }
                }
            }
        } catch (Exception e) {
            throw new HException("decoderModel hbase return value error.", e);
        }
        return t;
    }

    private Object paseBaseType(String typeName, String value) throws ParseException {
        Object obj = null;
        if (types.contains(typeName)) {
            if ("java.util.Date".equalsIgnoreCase(typeName)) {
                obj = DateUtils.strToDate(value);
            }
            if ("java.lang.Integer".equalsIgnoreCase(typeName) || "int".equalsIgnoreCase(typeName)) {
                obj = Integer.parseInt(value);
            }
            if ("java.lang.Double".equalsIgnoreCase(typeName) || "double".equalsIgnoreCase(typeName)) {
                obj = Double.parseDouble(value);
            }
            if ("java.lang.Float".equalsIgnoreCase(typeName) || "float".equalsIgnoreCase(typeName)) {
                obj = Float.parseFloat(value);
            }
            if ("java.lang.Long".equalsIgnoreCase(typeName) || "long".equalsIgnoreCase(typeName)) {
                obj = Long.parseLong(value);
            }
            if ("java.lang.Short".equalsIgnoreCase(typeName) || "short".equalsIgnoreCase(typeName)) {
                obj = Short.parseShort(value);
            }
            if ("java.lang.Byte".equalsIgnoreCase(typeName) || "byte".equalsIgnoreCase(typeName)) {
                obj = Byte.parseByte(value);
            }
            if ("java.lang.Boolean".equalsIgnoreCase(typeName) || "boolean".equalsIgnoreCase(typeName)) {
                obj = Boolean.parseBoolean(value);
            }
            if ("java.lang.Character".equalsIgnoreCase(typeName) || "char".equalsIgnoreCase(typeName)) {
                char[] chars = value.toCharArray();
                obj = chars[0];
            }
            if ("java.lang.String".equalsIgnoreCase(typeName)) {
                obj = value;
            }
        } else {
            try {
                Class<?> aclass = Class.forName(typeName);
                obj = JsonUtils.fromJson(value, aclass);
            } catch (ClassNotFoundException e) {
                logger.error("hbase 解析返回数据类型转换异常："+typeName,e);
            }
        }
        return obj;
    }

    /**
     * 获取属性值
     *
     * @param desc
     * @param obj
     * @return
     */
    private HEntity.DataModel getFieldValue(HEntitySkeleton.FiledDesc desc, Object obj) {
        try {
            Field filed = desc.getFiled();
            filed.setAccessible(true);
            Object val = filed.get(obj);
            if (val != null) {
                HEntity.DataModel filedData = new HEntity.DataModel();
                filedData.setQualifier(desc.getQualifier());
                filedData.setColumnFamily(desc.getColumnFamily());
                String filedVal = null;
                //得到类型
                String typeName = desc.getType();
                boolean contains = types.contains(typeName);
                //如果类型是基础类型的时间类型，
                if ("java.util.Date".equalsIgnoreCase(typeName)) {
                    filedVal = DateUtils.dateToStr((Date) val);
                } else if (contains) {
                    filedVal = val.toString();
                } else {
                    filedVal = JsonUtils.toJson(val);
                }
                filedData.setFieldValue(filedVal);
                return filedData;
            }
            return null;
        } catch (IllegalAccessException e) {
            logger.error("hbase 获取对象属性异常：", e);
            throw new HException(e);
        }
    }


    /**
     * 获取行健值
     *
     * @param desc          属性结构
     * @param obj           对象
     * @param generatorEnum 策略方式
     * @return
     */
    private String getRowKey(HEntitySkeleton.FiledDesc desc, Object obj, IdGeneratorEnum generatorEnum) {
        HEntity.DataModel fieldValue = getFieldValue(desc, obj);
        if (fieldValue != null) {
            String rowKey = fieldValue.getFieldValue();
            rowKey = generator.rowKey(rowKey);
            return rowKey;
        }
        throw new HException("rowKey is null");
    }


    /**
     * 获取行健值
     *
     * @param obj           对象
     * @param generatorEnum 策略方式
     * @return
     */
    private String getRowKey(Serializable obj, IdGeneratorEnum generatorEnum) {
        if (obj != null) {
            String rowKey = String.valueOf(obj);
            rowKey = generator.rowKey(rowKey);
            return rowKey;
        }
        throw new HException("rowKey is null");
    }

    /**
     * 构建rowkey
     *
     * @param rowKey
     * @param skeleton
     * @return
     */
    @Override
    public HEntity getPerRowKey(Serializable rowKey, HEntitySkeleton skeleton) {
        HEntity entity = new HEntity();
        entity.setTableSpace(configuration.getTableSpace());
        entity.setRowKey(getRowKey(rowKey, skeleton.getGeneratorEnum()));
        entity.setTableName(skeleton.getTableName());
        return entity;
    }
}
